home *** CD-ROM | disk | FTP | other *** search
- /* Low level AX.25 frame processing - address header and routing */
- /* */
- /* 9205xx DAMA by DL1BKE */
- /* 9409xx DAMA bugfixes, T3 handling, T6 timeout, flushed state */
- /* by DG1ZX/DL6ZBA */
- /* 940920 fixed bad pointers in ax_recv() axheard traffic fixed */
- /* by DC0HK */
- /* 940925 fixed problem with ip.tos=16 (low_delay) forceing DA */
- /* mode when we are active in a VC mode connection */
- /* by DC0HK */
- /* 940930 fixed problem with flexnet search */
- /* fixed T4 timer digi busy sent RNR wnos now does not */
- /* poll after T4 expire */
- /* will never send any UI-frames if there is a dama_slave */
- /* connection exist on the interface, wait for new info */
- /* from dama developers */
- /* by DG1ZX/DL6ZBA */
- /* 941019 added retries in dama_flush and fixes problems with */
- /* multiples received DISCs. */
- /* Fixed bug when using WNOS as digipeater with dama link */
- /* at one side and non dama on the other port */
- /* by DG1ZX/DL6ZBA */
- /* */
-
- #include <stdio.h>
- #include <ctype.h>
- #include "global.h"
- #include "config.h"
- #include "socket.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "timer.h"
- #include "arp.h"
- #include "slip.h"
- #include "ax25.h"
- #ifdef NETROM
- #include "netrom.h"
- #endif
- #include "ip.h"
- #include "tcp.h"
- #include "trace.h"
- #include "files.h"
- #include "icmp.h"
-
- #define axptr(a) ((struct ax25_addr *) (a))
- #define next_seq(n) (((n) + 1) & MMASK)
-
- char Mycall[AXALEN] = "\0";
- char Nomycall[] = "Mycall not set\n";
-
- #ifdef NETROM
- extern void nr_derate __ARGS((struct ax25_cb *axp));
- #endif
-
- struct ax25_cb *Ax25_cb = NULLAX25;
- struct iface *axroute_default_ifp = NULLIF;
- struct axroute_tab *axroute_tab[AXROUTESIZE];
-
- static struct ax25_cb * near cr_ax25 __ARGS((char *remote,char *local,struct iface *iface));
-
- static int near axproto_recv __ARGS((struct iface *ifp,struct mbuf *bp,char repeated));
- static int near axroute __ARGS((struct ax25_cb *cp,struct mbuf *bp));
- static int near hash_function __ARGS((char *call,int rel));
- static int near space_ax25 __ARGS((struct ax25_cb *cp));
- static int near put_reseq __ARGS((struct ax25_cb *cp,struct mbuf *bp,int ns));
- static int near is_flexnet __ARGS((char *call,int store));
- static int near busy __ARGS((struct ax25_cb *cp));
- static void near init_timer __ARGS((struct ax25_cb *axp));
- static void near setaxstate __ARGS((struct ax25_cb *axp,int newstate));
- static void near send_packet __ARGS((struct ax25_cb *cp,int type,int cmdrsp,struct mbuf *data));
- static void near send_ack __ARGS((struct ax25_cb *cp,int cmdrsp));
- static void near try_send __ARGS((struct ax25_cb *cp,int fill_sndq,int mode));
- static void near inc_t1 __ARGS((struct ax25_cb *cp));
- static void near reset_t1 __ARGS((struct ax25_cb *cp));
- static void near dama_on __ARGS((struct iface *ifp));
- static void near dama_off __ARGS((struct iface *ifp));
- static void near dama_flush __ARGS((struct ax25_cb *cp));
-
- /* Default AX.25 parameters */
- int16 T1init = 10; /* Retransmission timeout */
- int16 T2init = 2; /* Acknowledgement delay timeout */
- int16 T3init = 600; /* keep-alive polling */
- int16 T4init = 60; /* Busy timeout */
- int16 T5init = 1; /* Packet assembly timeout */
- int16 T6init = 300; /* DAMA timeout */
- int16 Maxframe = 2; /* Stop and wait */
- int16 Retries = 10; /* 10 retries */
- int16 Axwindow = 2048; /* 2K incoming text before RNR'ing */
- int16 Paclen = 256; /* 256-byte I fields */
- int16 Pthresh = 64; /* Send polls for packets larger than this */
- int16 Digipeat = 2; /* Controls digipeating */
- int T3disc = 1; /* 0 = polling, 1 = disconnecting */
-
- /* List of AX.25 multicast addresses in network format (shifted ascii).
- * Only the first entry is used for transmission, but an incoming
- * packet with any one of these destination addresses is recognized
- * as a multicast.
- */
- char Ax25multi[][AXALEN] = {
- 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1, /* QST */
- 'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1, '0'<<1, /* NODES */
- 'I'<<1, 'D'<<1, ' '<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1, /* ID */
- /* 'M'<<1, 'A'<<1, 'I'<<1, 'L'<<1, ' '<<1, ' '<<1, '0'<<1, /* MAIL */
- /* 'O'<<1, 'P'<<1, 'E'<<1, 'N'<<1, ' '<<1, ' '<<1, '0'<<1, /* OPEN */
- /* 'C'<<1, 'Q'<<1, ' '<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1, /* CQ */
- /* 'B'<<1, 'E'<<1, 'A'<<1, 'C'<<1, 'O'<<1, 'N'<<1, '0'<<1, /* BEACON */
- 'R'<<1, 'M'<<1, 'N'<<1, 'C'<<1, ' '<<1, ' '<<1, '0'<<1, /* RMNC */
- /* 'A'<<1, 'L'<<1, 'L'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1, /* ALL */
- 'F'<<1, 'L'<<1, 'X'<<1, 'N'<<1, 'E'<<1, 'T'<<1, '0'<<1, /* FLXNET */
- '\0',
- };
-
- /* New-style frame segmenter. Returns queue of segmented fragments, or
- * original packet if small enough
- *
- * struct mbuf *bp; Complete packet
- * int16 ssize; Max size of frame segments
- */
-
- #ifdef NETROM
- struct mbuf *
- #else
- static struct mbuf *
- #endif
- segmenter(struct mbuf *bp,int16 ssize) {
- struct mbuf *bp1, *bptmp, *result = NULLBUF;
- int16 len, offset = 0;
- int segments;
-
- /* See if packet is too small to segment. Note 1-byte grace factor
- * so the PID will not cause segmentation of a 256-byte IP datagram.
- */
- if((len = len_p(bp)) <= ssize + 1)
- return bp; /* Too small to segment */
-
- ssize -= 2; /* ssize now equal to data portion size */
- segments = 1 + (len - 1) / ssize; /* # segments */
-
- while(segments != 0){
- offset += dup_p(&bptmp,bp,offset,ssize);
- if(bptmp == NULLBUF){
- free_q(&result);
- break;
- }
- /* Make room for segmentation header */
- if((bp1 = pushdown(bptmp,2)) == NULLBUF){
- free_p(bptmp);
- free_q(&result);
- break;
- }
- bp1->data[0] = PID_SEGMENT;
- bp1->data[1] = --segments;
- if(offset == ssize)
- bp1->data[1] |= SEG_FIRST;
- enqueue(&result,bp1);
- }
- free_p(bp);
- return result;
- }
-
- /* Send IP datagrams across an AX.25 link */
- int
- ax_send(struct mbuf *bp,struct iface *iface,int32 gateway,
- int prec,int del,int tput,int rel) {
- char *hw_addr;
- struct ax25_cb *axp, *axp1;
- struct mbuf *tbp;
- int16 mode;
- struct ip bp1;
- struct arp_tab *arp;
- struct connection conn;
- struct tcp seg;
- struct tcb *tcb;
-
-
- if(gateway == iface->broadcast) /* This is a broadcast IP datagram */
- return (*iface->output)(iface,Ax25multi[0],iface->hwaddr,PID_IP,bp);
-
- if((arp = arp_lookup(ARP_AX25,gateway)) != NULLARP && arp->state == ARP_VALID) {
- hw_addr = arp->hw_addr;
- mode = arp->flags;
- } else
- if((hw_addr = res_arp(iface,ARP_AX25,gateway,bp)) == NULLCHAR)
- return 0; /* Wait for address resolution */
-
- /* remove 'del' because tos = 16 foreces da_mode (dc0hk.940925) */
-
- if(/* del || */ (!rel && (mode == DATAGRAM_MODE)) || addreq(hw_addr,Ax25multi[0]))
- mode = DATAGRAM_MODE;
-
- if(mode == DATAGRAM_MODE)
- /* Use UI frame */
- return (*iface->output)(iface,hw_addr,iface->hwaddr,PID_IP,bp);
-
- if((axp = find_ax25(hw_addr,iface->hwaddr)) == NULLAX25) {
- /* Open a new connection */
- if((axp1 = open_ax25(iface,iface->hwaddr,hw_addr,
- AX_ACTIVE,s_arcall,s_atcall,s_ascall,-2)) == NULLAX25)
- goto quit;
- axp1->mode = DGRAM;
- }
-
- if(axp == NULLAX25) {
- axp = axp1;
- if(axp->state == DISCONNECTED)
- setaxstate(axp,CONNECTING);
- axp->user = 0;
- }
-
- dup_p(&tbp,bp,0,len_p(bp));
- if (ntohip(&bp1,&tbp) != -1)
- if (ntohtcp(&seg,&tbp) != -1) {
- conn.local.port = seg.source;
- conn.local.address = bp1.source;
- conn.remote.port = seg.dest;
- conn.remote.address = bp1.dest;
-
- if((tcb = lookup_tcb(&conn)) != NULLTCB && len_p(tbp) > 0
- && tcb->state != TCP_TIME_WAIT) {
- set_timer(&tcb->timer,10 * dur_timer(&tcb->timer));
- if(dur_timer(&tcb->timer) > 300000L)
- set_timer(&tcb->timer,300000L);
- start_timer(&tcb->timer);
- }
- }
- free_p(tbp);
-
- /* discard IP frames and send a SOURCE_QUENCH if there already are bytes
- * in the txq - DC0HK.920401 */
- if(len_p(axp->txq) > axp->iface->mtu) {
- ntohip(&bp1,&bp);
- icmp_output(&bp1,bp,ICMP_QUENCH,0,NULL);
- goto quit;
- }
-
- /* Insert the PID */
- if((tbp = pushdown(bp,1)) == NULLBUF)
- goto quit;
-
- tbp->data[0] = (mode == IPCAM_MODE) ? PID_NO_L3 : PID_IP;
-
- if((bp = segmenter(tbp,axp->iface->flags->paclen)) == NULLBUF)
- goto quit;
-
- send_ax25(axp,bp,DGRAM);
- return 0;
- quit:
- free_p(bp);
- return -1;
- }
-
- /* Add header and send connectionless (UI) AX.25 packet. */
- /* Note that the calling order here must match enet_output */
- /* since ARP also uses it. */
- /* */
- /* struct iface *iface; Interface to use; overrides routing table */
- /* char *dest; Destination AX.25 address (7 bytes, shifted) */
- /* char *source; Source AX.25 address (7 bytes, shifted) */
- /* int16 pid; Protocol ID */
- /* struct mbuf *data; Data field (follows PID) */
- int
- ax_output(struct iface *iface,char *dest,char *source,int16 pid,
- struct mbuf *data) {
- struct mbuf *abp, *cbp;
- struct iface *ifp;
- struct axroute_tab *rp;
- int ndigis = 0, fill = 0;
-
- /* discard UI frames if the respective interface is in DAMA slave mode */
- if ( iface->flags->dama_slave ) {
- free_p(data);
- return -1;
- }
-
- /* Allocate mbuf for control and PID fields, and fill in */
- if((cbp = pushdown(data,2)) == NULLBUF) {
- free_p(data);
- return -1;
- }
- cbp->data[0] = UI;
- cbp->data[1] = pid;
-
- if((rp = axroute_tabptr(axptr(dest),0)) != 0)
- for( ; rp; rp = rp->digi) {
- ifp = rp->ifp;
- if(!fill) {
- fill = 1;
- continue;
- }
- if((abp = pushdown(cbp,AXALEN)) == NULLBUF) {
- free_p(cbp);
- return -1;
- }
- memcpy(abp->data,rp->call.call,ALEN);
- abp->data[ALEN] = rp->call.ssid;
- if(ndigis)
- abp->data[ALEN] &= ~E;
- else {
- abp->data[ALEN] |= E;
- ndigis = 1;
- }
- cbp = abp;
- }
- else
- ifp = iface;
-
- if((abp = pushdown(cbp,2 * AXALEN)) == NULLBUF) {
- free_p(cbp);
- return -1;
- }
- memcpy(abp->data,dest,AXALEN);
- abp->data[ALEN] &= ~E;
- abp->data[ALEN] &= ~C;
- memcpy(abp->data + AXALEN,source,AXALEN);
- if(ndigis)
- abp->data[ALEN + AXALEN] &= ~E;
- else
- abp->data[ALEN + AXALEN] |= E;
- abp->data[ALEN + AXALEN] &= ~C;
-
- if (ifp) {
- if (ifp->forw)
- ifp = ifp->forw;
- ifp->rawsndcnt++;
- ifp->lastsent = secclock();
- return (*ifp->raw)(ifp,abp);
- } else {
- free_p(abp);
- return -1;
- }
- }
-
- static int near
- hash_function(char *call,int rel) {
- int32 hashval = ((int32)(*call++ << 23) & 0x0f000000L);
-
- hashval |= ((int32)(*call++ << 19) & 0x00f00000L);
- hashval |= ((int32)(*call++ << 15) & 0x000f0000L);
- hashval |= ((int32)(*call++ << 11) & 0x0000f000L);
- hashval |= ((int32)(*call++ << 7) & 0x00000f00L);
- hashval |= ((int32)(*call++ << 3) & 0x000000f0L);
- hashval |= ((int32)(*call >> 1) & 0x0000000fL);
- return (int)(hashval % rel);
- }
-
- struct axroute_tab *
- axroute_tabptr(struct ax25_addr *call,int create) {
- struct axroute_tab *rp;
- int hashval = hash_function((char *)call,AXROUTESIZE);
-
- for (rp = axroute_tab[hashval]; rp && !addreq((char *) &rp->call, (char *) call); rp = rp->next) ;
- if (!rp && create) {
- rp = (struct axroute_tab *)mxallocw(sizeof(struct axroute_tab));
- rp->call = *call;
- rp->next = axroute_tab[hashval];
- axroute_tab[hashval] = rp;
- }
- return rp;
- }
-
- void
- axroute_add(struct ax25_cb *cp,int perm)
- {
-
- int i, ncalls = 0;
- char *ap;
- struct axroute_tab *rp, *lastnode = 0;
- struct ax25_addr calls[MAXDIGIS + 1];
-
- for (ap = cp->path + AXALEN; !addreq(ap,cp->iface->hwaddr); ap += AXALEN) ;
-
- do {
- ap += AXALEN;
- if (ap >= cp->path + cp->pathlen) ap = cp->path;
- if (!*ap || addreq(ap,cp->iface->hwaddr)) return;
- for (i = 0; i < ncalls; i++)
- if (addreq((char *) (calls + i), ap)) return;
- calls[ncalls++] = *axptr(ap);
- } while (ap != cp->path);
-
- for (i = 0; i < ncalls; i++) {
- rp = axroute_tabptr(calls + i, 1);
- if (perm || !rp->perm) {
- if (lastnode) {
- rp->digi = lastnode;
- rp->ifp = 0;
- } else {
- rp->digi = 0;
- rp->ifp = cp->iface;
- }
- rp->perm = perm;
- }
- rp->time = currtime;
- lastnode = rp;
- }
- }
-
- static int near
- axroute(struct ax25_cb *cp,struct mbuf *bp) {
- char *dest;
- struct axroute_tab *rp;
- struct iface *ifp;
-
- if (cp && cp->iface)
- ifp = cp->iface;
- else {
- if (bp->data[AXALEN + ALEN] & E)
- dest = bp->data;
- else
- for (dest = bp->data + 2 * AXALEN; ; dest += AXALEN) {
- if (!(dest[ALEN] & REPEATED))
- break;
- if (dest[ALEN] & E) {
- dest = bp->data;
- break;
- }
- }
- rp = axroute_tabptr(axptr(dest),0);
- ifp = (rp && rp->ifp) ? rp->ifp : axroute_default_ifp;
- }
-
- if (ifp && (ifp->flags->dama_slave == 0 || ifp->flags->dama_busy == 0) ) {
- if (ifp->forw)
- ifp = ifp->forw;
- ifp->rawsndcnt++;
- ifp->lastsent = secclock();
- (*ifp->raw)(ifp, bp);
- }
- else
- free_p(bp);
- return;
- }
-
- static void near
- send_packet(struct ax25_cb *cp,int type,int cmdrsp,struct mbuf * data) {
- int control = type;
- struct mbuf *bp = ambufw(cp->pathlen + 1);
- char *p = bp->data;
-
- memcpy(p, cp->path, cp->pathlen);
- if (cmdrsp & DST_C) p[ALEN] |= C;
- if (cmdrsp & SRC_C) p[ALEN + AXALEN] |= C;
- p += cp->pathlen;
-
- if (type == I) {
- control |= (cp->vs << 1);
- cp->vs = next_seq(cp->vs);
- }
- if ((type & 3) != U) {
- control |= (cp->vr << 5);
- stop_timer(&cp->t2);
- }
- if (cmdrsp & PF) control |= PF;
- *p++ = control;
-
- if (type == RR || type == REJ || type == UA)
- cp->rnrsent = 0;
- if (type == RNR)
- cp->rnrsent = 1;
- if (type == REJ)
- cp->rejsent = 1;
- if (cmdrsp == POLL)
- cp->polling = 1;
- if (type == I || cmdrsp == POLL)
- start_timer(&cp->t1);
- if (type == I) {
- start_timer(&cp->t3);
- start_timer(&cp->t6);
- }
- bp->cnt = p - bp->data;
- bp->next = data;
- axroute(cp, bp);
- }
-
- void
- ax_recv(struct iface *iface,struct mbuf * bp) {
- char axheader[10*AXALEN+1], (*mpp)[AXALEN], *ap, *cntrlptr;
- int addrsize, pid, multicast = 0;
- struct ax25_cb axp;
-
- if (!(bp && bp->data)) goto discard;
- if (is_bud(bp->data + AXALEN,0)) goto discard;
- for (cntrlptr = bp->data; !(*cntrlptr++ & E); ) ;
- addrsize = (int)(cntrlptr - bp->data);
- if (addrsize < 2 * AXALEN || addrsize >= bp->cnt ||
- addrsize > 10 * AXALEN || addrsize % AXALEN)
- goto discard;
-
- if(addrsize == 2 * AXALEN)
- logaddr(iface,bp->data + AXALEN,cntrlptr[1]); /* fix dc0hk.940920 */
- else {
- for (ap = bp->data + 2 * AXALEN; ap < cntrlptr; ap += AXALEN)
- if (!(ap[ALEN] & REPEATED)) {
- logaddr(iface,ap - AXALEN,cntrlptr[1]); /* fix dc0hk.940920 */
- if (!addreq(ap,iface->hwaddr))
- goto discard;
- ap[ALEN] |= REPEATED;
- switch (iface->flags->digipeat) {
- case 2:
- axproto_recv(iface, bp, 0);
- return;
- case 1:
- axroute(NULLAX25, bp);
- return;
- default:
- goto discard;
- }
- }
- logaddr(iface,ap - AXALEN,cntrlptr[1]); /* fix dc0hk.940920 */
- }
-
- if ((*cntrlptr & ~PF) != UI) {
- if (!addreq(bp->data,iface->hwaddr)
- && (find_ax25(bp->data + AXALEN,bp->data) == NULLAX25))
- goto discard;
- axproto_recv(iface, bp, 1);
- return;
- }
- if (addreq(bp->data,iface->hwaddr))
- goto jump;
-
- /* Examine immediate destination for a multicast address */
- for(mpp = Ax25multi;(*mpp)[0] != '\0';mpp++)
- if(addreq(bp->data,*mpp)){
- multicast = 1;
- goto jump;
- }
- goto discard;
-
- jump:
- pullup(&bp, axheader, addrsize + 1);
- pid = PULLCHAR(&bp);
- if (!bp)
- return;
-
- if(!multicast)
- build_path(&axp,iface,axheader,1,0);
-
- switch (pid) {
- case PID_IP:
- if (bp->cnt >= 20) {
- struct arp_tab *arp;
-
- if ((arp = arp_add( /* src_ipaddr */
- get32(&bp->data[12]),ARP_AX25,axheader + AXALEN,0,0)) != NULLARP) {
- stop_timer(&arp->timer);
- set_timer(&arp->timer,0L);
- }
- }
- ip_route(iface,iface,bp,multicast);
- return;
- case PID_ARP:
- arp_input(iface, bp);
- return;
- #ifdef NETROM
- case PID_NETROM:
- nr_nodercv(iface,axheader + AXALEN,bp);
- return;
- #endif
- #ifdef AX25
- case PID_NO_L3: /* FLEXNET-Search should now be answered */
- if(!multicast && Attended) {
- iface->flags->dama_busy = 0;
- send_packet(&axp,DM,FINAL,NULLBUF);
- if(iface->flags->dama_slave)
- iface->flags->dama_busy = 1;
- }
- #endif
- default:
- goto discard;
- }
-
- discard:
- free_p(bp);
- }
-
- #ifdef AXIP
- static int32 axipaddr[NAX25]; /* table of IP addresses of AX.25 interfaces */
-
- /*
- * FCS lookup table as generated by fcsgen.c
- */
- static int16 near fcstab[256] = {
- 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
- 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
- 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
- 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
- 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
- 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
- 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
- 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
- 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
- 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
- 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
- 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
- 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
- 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
- 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
- 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
- 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
- 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
- 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
- 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
- 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
- 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
- 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
- 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
- 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
- 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
- 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
- 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
- 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
- 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
- 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
- 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
- };
-
- /* raw routine for sending AX.25 on top of IP */
- static int
- axip_raw(iface,bp)
- struct iface *iface; /* Pointer to interface control block */
- struct mbuf *bp; /* Data field */
- {
- int16 len = len_p(bp), fcs = 0xffff;
- struct mbuf *bp1;
-
- if(dup_p(&bp1,bp,0,len) != len) {
- free_p(bp);
- return -1;
- }
- while (len--) /* calculate FCS */
- fcs = (fcs >> 8) ^ fcstab[(fcs ^ PULLCHAR(&bp1)) & 0x00ff];
-
- fcs ^= 0xffff; /* final FCS (is this right?) */
- bp1 = ambufw(sizeof(fcs));
- *bp1->data = fcs & 0xff;
- *(bp1->data+1) = (fcs >> 8) & 0xff;
- bp1->cnt += sizeof(fcs);
- append(&bp,bp1);
- return ip_send(INADDR_ANY,axipaddr[iface->dev],AX25_PTCL,0,0,bp,0,0,0);
- }
-
- /* Handle AX.25 frames received inside IP according to RFC-1226 */
- void
- axip_input(iface,ip,bp,rxbroadcast)
- struct iface *iface; /* Input interface */
- struct ip *ip; /* IP header */
- struct mbuf *bp; /* AX.25 frame with FCS */
- int rxbroadcast; /* Accepted for now */
- {
- int i;
- struct mbuf *tbp;
- int16 len, f, fcs = 0xffff;
-
- /* Since the AX.25 frame arrived on an interface that does
- not necessarily support AX.25, we have to find a suitable
- AX.25 interface, or drop the packet.
- */
- /* Try to find a matching AX.25 pseudo interface */
- for(i=0; i < NAX25; ++i)
- if(axipaddr[i] == ip->source)
- break;
- if(i == NAX25) {
- /* Here we could still try to pick a real AX.25 interface,
- but that would mean that we are accepting AX.25 frames
- from unknown IP hosts, so we'd rather drop it.
- */
- free_p(bp);
- return;
- }
- for(iface = Ifaces; iface != NULLIF; iface = iface->next) {
- if(iface->raw == axip_raw && iface->dev == i)
- /* found the right AX.25 pseudo interface */
- break;
- }
- if(iface == NULLIF) {
- free_p(bp);
- return;
- }
- iface->rawrecvcnt++;
- iface->lastrecv = secclock();
- len = len_p(bp) - sizeof(fcs);
- if(dup_p(&tbp,bp,0,len) != len) {
- free_p(bp);
- return;
- }
- while(len--)
- fcs = (fcs >> 8) ^ fcstab[(fcs ^ PULLCHAR(&bp)) & 0x00ff];
- fcs ^= 0xffff;
- f = PULLCHAR(&bp);
- f |= (PULLCHAR(&bp) << 8);
- if(fcs == f)
- ax_recv(iface,tbp);
- else
- free_p(tbp);
- }
- #endif /* AXIP */
-
- static void near
- reset_t1(cp)
- struct ax25_cb *cp;
- {
- int32 tmp = 4 * cp->mdev + cp->srt;
-
- if(tmp > 3000 * cp->iface->flags->t1init)
- tmp = 3000 * cp->iface->flags->t1init;
- if(tmp < 2000)
- tmp = 2000;
-
- set_timer(&cp->t1,tmp);
- }
-
- static void near
- inc_t1(cp)
- struct ax25_cb *cp;
- {
- int32 tmp = (dur_timer(&cp->t1) * 5 + 2) / 4;
-
- if(tmp > 3000 * cp->iface->flags->t1init)
- tmp = 3000 * cp->iface->flags->t1init;
- if(tmp < 2000)
- tmp = 2000;
-
- set_timer(&cp->t1,tmp);
- }
-
- static int near
- space_ax25(struct ax25_cb *cp) {
- int cnt;
-
- if (cp) {
- switch (cp->state) {
- case CONNECTING:
- case CONNECTED:
- if (!cp->closed) {
- cnt = (cp->cwind - cp->unack) * cp->iface->flags->paclen - (len_p(cp->txq) -1);
- return (cnt > 0) ? cnt : 0;
- }
- }
- }
- return -1;
- }
-
- static int near
- busy(cp)
- struct ax25_cb *cp;
- {
- return cp->peer ? space_ax25(cp->peer) <= 0
- : len_p(cp->rxq) >= cp->iface->flags->axwindow;
- }
-
- static void near
- send_ack(struct ax25_cb *cp,int cmdrsp) {
- if (busy(cp))
- send_packet(cp, RNR, cmdrsp, NULLBUF);
- else if (!cp->dama && !cp->rejsent
- && (cp->reseq[0].bp || cp->reseq[1].bp || cp->reseq[2].bp ||
- cp->reseq[3].bp || cp->reseq[4].bp || cp->reseq[5].bp ||
- cp->reseq[6].bp || cp->reseq[7].bp))
- send_packet(cp, REJ, cmdrsp, NULLBUF);
- else if (cp->dama
- && (cp->reseq[0].bp || cp->reseq[1].bp || cp->reseq[2].bp ||
- cp->reseq[3].bp || cp->reseq[4].bp || cp->reseq[5].bp ||
- cp->reseq[6].bp || cp->reseq[7].bp))
- send_packet(cp, REJ, cmdrsp, NULLBUF);
- else
- send_packet(cp, RR, cmdrsp, NULLBUF);
- }
-
- static void near
- try_send(struct ax25_cb *cp,int fill_sndq,int mode) {
- int cnt;
- struct mbuf *bp, *tbp;
-
- stop_timer(&cp->t5);
- while (cp->unack < cp->cwind) {
- if (cp->state != CONNECTED || cp->remotebusy)
- return;
- if (fill_sndq && cp->t_upcall) {
- if((cnt = space_ax25(cp)) > 0) {
- (*cp->t_upcall)(cp, cnt);
- if (cp->unack >= cp->cwind) return;
- }
- }
- if (!cp->txq) return;
- if (mode == STREAM) {
- cnt = len_p(cp->txq);
- if (cnt < cp->iface->flags->paclen) {
- if (cp->unack)
- return;
- if (!cp->peer && cp->sndqtime + cp->iface->flags->t5init * 1000L > msclock()) {
- set_timer(&cp->t5,(cp->sndqtime + cp->iface->flags->t5init * 1000L - msclock()));
- start_timer(&cp->t5);
- return;
- }
- }
- if (cnt > cp->iface->flags->paclen)
- cnt = cp->iface->flags->paclen;
- bp = ambufw(cnt);
- pullup(&cp->txq, bp->data, bp->cnt = cnt);
- tbp = pushdown(bp,1);
- tbp->data[0] = PID_NO_L3;
- bp = tbp;
- } else {
- bp = dequeue(&cp->txq);
- }
- enqueue(&cp->rxasm, bp);
- cp->unack++;
- cp->sndtime[cp->vs] = msclock();
- dup_p(&bp, bp, 0, MAXINT16);
- send_packet(cp, I, CMD, bp);
- }
- }
-
- static void near
- setaxstate(struct ax25_cb *cp,int newstate) {
- int oldstate = cp->state;
-
- cp->state = newstate;
- cp->polling = 0;
- cp->retries = 0;
- cp->flushed = 0;
- stop_timer(&cp->t1);
- stop_timer(&cp->t2);
- stop_timer(&cp->t4);
- stop_timer(&cp->t5);
- if (!cp->dama)
- reset_t1(cp);
-
- switch (newstate) {
- case DISCONNECTED:
- if (cp->peer)
- disc_ax25(cp->peer);
- if (cp->s_upcall)
- (*cp->s_upcall)(cp, oldstate, newstate);
- if (cp->peer && cp->peer->state == DISCONNECTED) {
- if (cp->peer->dama && (--cp->peer->iface->flags->dama_slave == 0))
- dama_off(cp->peer->iface);
- del_ax25(cp->peer);
- cp->peer = cp->peer->peer = NULLAX25;
- }
- break;
- case CONNECTING:
- if (cp->s_upcall)
- (*cp->s_upcall)(cp, oldstate, newstate);
- send_packet(cp, SABM, POLL, NULLBUF);
- break;
- case CONNECTED:
- if (cp->peer && cp->peer->state == DISCONNECTED) {
- send_packet(cp->peer, UA, FINAL, NULLBUF);
- setaxstate(cp->peer, CONNECTED);
- }
- if (cp->s_upcall)
- (*cp->s_upcall)(cp, oldstate, newstate);
- if (!cp->dama)
- try_send(cp, 1, cp->mode);
- break;
- case DISCONNECTING:
- if (cp->peer) {
- disc_ax25(cp->peer);
- cp->peer = cp->peer->peer = NULLAX25;
- }
- if (cp->s_upcall)
- (*cp->s_upcall)(cp, oldstate, newstate);
- send_packet(cp, DISC, POLL, NULLBUF);
- break;
- }
- }
-
- /* timers T1 T2 T3 T4 T5 T6 */
-
- static void /* t1_timer */
- t1_timeout(struct ax25_cb *cp) {
- inc_t1(cp);
- cp->cwind = 1;
- cp->retries++;
-
- switch (cp->state) {
- case DISCONNECTED:
- break;
- case CONNECTING:
- if (cp->peer && cp->peer->state == DISCONNECTED)
- if (cp->retries > 2) {
- cp->reason = LB_TIMEOUT;
- setaxstate(cp, DISCONNECTED);
- #ifdef NETROM
- nr_derate(cp);
- #endif
- } else
- start_timer(&cp->t1);
- else if (cp->retries > cp->iface->flags->retries) {
- cp->reason = LB_TIMEOUT;
- setaxstate(cp, DISCONNECTED);
- #ifdef NETROM
- nr_derate(cp);
- #endif
- }
- else
- send_packet(cp, SABM, POLL, NULLBUF);
- break;
- case CONNECTED:
- if (cp->retries > (cp->iface->flags->retries * 2)) {
- cp->reason = LB_TIMEOUT;
- setaxstate(cp, DISCONNECTED);
- #ifdef NETROM
- nr_derate(cp);
- #endif
- } else
- if (!cp->polling && !cp->remotebusy && cp->unack && !cp->dama
- && len_p(cp->rxasm) - 1 <= cp->iface->flags->pthresh) {
- int old_vs;
- struct mbuf *bp;
- old_vs = cp->vs;
- cp->vs = (cp->vs - cp->unack) & 7;
- cp->sndtime[cp->vs] = 0;
- dup_p(&bp, cp->rxasm, 0, MAXINT16);
- send_packet(cp, I, POLL, bp);
- cp->vs = old_vs;
- } else if (!cp->dama) {
- send_ack(cp, POLL);
- }
- break;
- case DISCONNECTING:
- if (cp->retries > (cp->iface->flags->retries / 2)) {
- cp->reason = LB_TIMEOUT;
- setaxstate(cp, DISCONNECTED);
- if (cp->dama && (--cp->iface->flags->dama_slave == 0) )
- dama_off(cp->iface);
- #ifdef NETROM
- nr_derate(cp);
- #endif
- } else
- send_packet(cp, DISC, POLL, NULLBUF);
- break;
- }
- }
-
- static void /* t2_timer */
- t2_timeout(struct ax25_cb *cp) {
- send_ack(cp, RESP);
- }
-
-
- static void t3_timeout(struct ax25_cb *cp) { /* t3_timer normal timeout */
- if (!run_timer(&cp->t1) && cp->state == CONNECTED) {
- if(cp->iface->flags->t3disc)
- disc_ax25(cp);
- else {
- if (!cp->dama)
- send_ack(cp, POLL);
- }
- }
- }
-
- static void /* t4_timer */
- t4_timeout(struct ax25_cb *cp) {
- if (!cp->polling && !cp->dama)
- send_ack(cp, POLL);
- }
-
- static void /* t5_timer */
- t5_timeout(struct ax25_cb *cp) {
- try_send(cp, 1, STREAM);
- }
-
-
- static void t6_timeout(struct ax25_cb *cp) { /* t6_timer dama timeout */
- if (!run_timer(&cp->t1) && cp->state == CONNECTED && cp->dama) {
- cp->dama = 0;
- if (-- cp->iface->flags->dama_slave == 0)
- dama_off(cp->iface);
-
- if ( cp->iface->flags->dama_slave && (cp->txq || cp->unack)) {
- /* we want to close the connection immediately after T1 is expired */
- cp->retries = cp->iface->flags->retries * 2;
- }
-
- start_timer(&cp->t1);
- disc_ax25(cp);
- }
- }
-
- /* Look up entry in connection table */
- struct ax25_cb *
- find_ax25(char *remote,char *local) {
- struct ax25_cb *axp, *axlast = NULLAX25;
-
- /* Search list */
- for(axp = Ax25_cb; axp != NULLAX25; axlast = axp, axp = axp->next){
- if(addreq(axp->path,remote) && addreq(axp->path + AXALEN,local)){
- if(axlast != NULLAX25) {
- /* Move entry to top of the list */
- axlast->next = axp->next;
- axp->next = Ax25_cb;
- Ax25_cb = axp;
- }
- return axp;
- }
- }
- return NULLAX25;
- }
-
- static void near
- init_timer(struct ax25_cb *axp)
- {
- if (axp->iface != NULLIF) {
- set_timer(&axp->t1,axp->iface->flags->t1init * 1000L);
- axp->t1.func = (void (*) __ARGS((void *))) t1_timeout;
- axp->t1.arg = axp;
-
- set_timer(&axp->t2,axp->iface->flags->t2init * 1000L);
- axp->t2.func = (void (*) __ARGS((void *))) t2_timeout;
- axp->t2.arg = axp;
-
- set_timer(&axp->t3,axp->iface->flags->t3init * 1000L);
- axp->t3.func = (void (*) __ARGS((void *))) t3_timeout;
- axp->t3.arg = axp;
-
- set_timer(&axp->t4,axp->iface->flags->t4init * 1000L);
- axp->t4.func = (void (*) __ARGS((void *))) t4_timeout;
- axp->t4.arg = axp;
-
- set_timer(&axp->t5,axp->iface->flags->t5init * 1000L);
- axp->t5.func = (void (*) __ARGS((void *))) t5_timeout;
- axp->t5.arg = axp;
-
- set_timer(&axp->t6,axp->iface->flags->t6init * 1000L);
- axp->t6.func = (void (*) __ARGS((void *))) t6_timeout;
- axp->t6.arg = axp;
- }
- }
-
- /* Create an ax25 control block. Allocate a new structure, if necessary,
- * and fill it with all the defaults. The caller
- * is still responsible for filling in the reply address
- */
- static struct ax25_cb * near
- cr_ax25(char *remote,char *local,struct iface *iface) {
- struct ax25_cb *axp;
-
- if(remote == NULLCHAR)
- return NULLAX25;
-
- if((axp = find_ax25(remote,local)) == NULLAX25){
- /* Not already in table; create an entry */
- axp = (struct ax25_cb *)mxallocw(sizeof(struct ax25_cb));
- axp->next = Ax25_cb;
- Ax25_cb = axp;
- }
- axp->state = DISCONNECTED;
- axp->cwind = 1;
- axp->user = -1;
- axp->iface = iface;
- init_timer(axp);
-
- /* Always to a receive and state upcall as default */
- /* Also bung in a default transmit upcall - in case */
- axp->r_upcall = s_arcall;
- axp->t_upcall = s_atcall;
- axp->s_upcall = s_ascall;
- axp->peer = NULLAX25;
- return axp;
- }
-
-
-
- /* Open an AX.25 connection */
- struct ax25_cb *
- open_ax25(iface,local,remote,mode,r_upcall,t_upcall,s_upcall,user)
- struct iface *iface; /* Interface */
- char *local; /* Local address */
- char *remote; /* Remote address */
- int mode; /* active/passive/server */
- void (*r_upcall)(); /* Receiver upcall handler */
- void (*t_upcall)(); /* Transmitter upcall handler */
- void (*s_upcall)(); /* State-change upcall handler */
- int user; /* User linkage area */
- {
- struct ax25_cb *axp = NULLAX25;
- char remtmp[AXALEN], path[3*AXALEN];
-
- if(remote == NULLCHAR){
- remote = remtmp;
- setcall(remote," ");
- }
- if((axp = find_ax25(remote,local)) != NULLAX25 && axp->state != DISCONNECTED)
- return NULLAX25; /* Only one to a customer */
- if(axp == NULLAX25 && (axp = cr_ax25(remote,local,iface)) == NULLAX25)
- return NULLAX25;
-
- axp->r_upcall = r_upcall;
- axp->t_upcall = t_upcall;
- axp->s_upcall = s_upcall;
- axp->user = (user == -2) ? -1 : user;
-
- memcpy(path,remote,AXALEN);
- path[ALEN] &= ~E;
- memcpy(path + AXALEN,local,AXALEN);
- path[ALEN + AXALEN] |= E;
-
- switch(mode) {
- case AX_SERVER:
- axp->clone = 1;
- case AX_PASSIVE: /* Note fall-thru */
- axp->state = LISTEN;
- return axp;
- case AX_ACTIVE:
- break;
- }
-
- build_path(axp,NULLIF,path,0,1);
-
- if(!axp->iface) {
- del_ax25(axp);
- return NULLAX25;
- }
-
- if(user == -2) {
- addrcp(axp->path + AXALEN,axp->iface->hwaddr);
- axp->path[axp->pathlen - 1] |= E;
- axroute_add(axp,0);
- }
-
- switch(axp->state){
- case DISCONNECTED:
- if(user != -2)
- setaxstate(axp,CONNECTING);
- break;
- case CONNECTING:
- free_q(&axp->txq);
- free_q(&axp->rxasm);
- break;
- case DISCONNECTING: /* Ignore */
- break;
- case CONNECTED:
- free_q(&axp->txq);
- setaxstate(axp,CONNECTING);
- break;
- }
- return axp;
- }
-
-
-
-
- int
- send_ax25(struct ax25_cb *cp,struct mbuf *bp,int pid) {
- /* pid: used as the connection mode indicator */
- int16 cnt;
-
- if (!(cp && bp)) {
- free_p(bp);
- return (-1);
- }
- cp->mode = pid;
- switch (cp->state) {
- case DISCONNECTED:
- free_p(bp);
- return (-1);
- case CONNECTING:
- case CONNECTED:
- if (!cp->closed) {
- if ((cnt = len_p(bp)) != 0) {
- if (pid == 0)
- append(&cp->txq, bp);
- else
- enqueue(&cp->txq, bp);
- cp->sndqtime = msclock();
- try_send(cp, 0, pid);
- }
- return (int)cnt;
- }
- case DISCONNECTING:
- free_p(bp);
- return (-1);
- }
- return (-1);
- }
-
- /* Receive incoming data on an AX.25 connection */
- struct mbuf *
- recv_ax25(struct ax25_cb *axp,int16 cnt) {
- struct mbuf *bp;
-
- if(!axp->rxq)
- return NULLBUF;
-
- if(cnt == 0 || axp->mode == DGRAM || axp->rcvcnt <= cnt){
- /* This means we want it all */
- bp = dequeue(&axp->rxq);
- cnt = len_p(bp);
- axp->rxq = NULLBUF;
- }
- else {
- bp = ambufw(cnt);
- bp->cnt = pullup(&axp->rxq,bp->data,cnt);
- }
- axp->rcvcnt -= cnt;
-
- /* If this has un-busied us, send a RR to reopen the window */
- if(axp->rnrsent && !busy(axp)) send_ack(axp,RESP);
-
- return bp;
- }
-
- /* Close an AX.25 connection */
- int
- disc_ax25(struct ax25_cb *axp) {
- if(axp == NULLAX25)
- return -1;
- if(axp->closed)
- return -1;
- axp->closed = 1;
- switch(axp->state){
- case LISTEN:
- del_ax25(axp);
- case DISCONNECTED:
- case DISCONNECTING:
- return -1;;
- case CONNECTED:
- if(!axp->txq && !axp->unack)
- setaxstate(axp,DISCONNECTING);
- return 0;
- case CONNECTING:
- setaxstate(axp, DISCONNECTED);
- return 0;
- }
- return -1;
- }
-
-
- /* Abruptly terminate an AX.25 connection */
- int
- reset_ax25(struct ax25_cb *axp) {
- void (*upcall)();
-
- if (axp == NULLAX25)
- return -1;
-
- if (axp->dama && (--axp->iface->flags->dama_slave == 0) ) {
- dama_off(axp->iface);
- axp->dama = 0;
- }
-
- upcall = axp->s_upcall;
- axp->reason = LB_DM;
- setaxstate(axp,DISCONNECTED);
- /* Clean up if the standard upcall isn't in use */
- if(upcall != s_ascall)
- del_ax25(axp);
- return 0;
- }
-
- /* Remove entry from connection table */
- void
- del_ax25(struct ax25_cb *conn) {
- struct ax25_cb *axp, *axlast = NULLAX25;
- int i;
-
- for(axp = Ax25_cb; axp != NULLAX25; axlast=axp,axp = axp->next){
- if(axp == conn)
- break;
- }
- if(axp == NULLAX25)
- return; /* Not found */
-
- /* Remove from list */
- if(axlast != NULLAX25)
- axlast->next = axp->next;
- else
- Ax25_cb = axp->next;
-
- /* Timers should already be stopped, but just in case... */
- stop_timer(&axp->t1);
- stop_timer(&axp->t2);
- stop_timer(&axp->t3);
- stop_timer(&axp->t4);
- stop_timer(&axp->t5);
- stop_timer(&axp->t6);
-
- /* Free allocated resources */
- for(i = 0; i < 8; i++) free_p(axp->reseq[i].bp);
- free_q(&axp->txq);
- free_q(&axp->rxasm);
- free_q(&axp->rxq);
- free_q(&axp->segasm);
- xfree((char *)axp);
- }
-
- /* Verify that axp points to a valid ax25 control block */
- int
- ax25val(struct ax25_cb *axp) {
- struct ax25_cb *axp1;
-
- if(axp == NULLAX25)
- return 0; /* Null pointer can't be valid */
- for(axp1 = Ax25_cb; axp1 != NULLAX25; axp1 = axp1->next)
- if(axp1 == axp)
- return 1;
- return 0;
- }
-
- /* Force a retransmission */
- int
- kick_ax25(struct ax25_cb *axp) {
- if(!ax25val(axp))
- return -1;
- t1_timeout(axp);
- return 0;
- }
-
- static void near
- dama_flush(struct ax25_cb *cp) {
- struct mbuf *bp1, *qp;
- struct ax25_cb *axp;
-
- cp->iface->flags->dama_busy = 0;
-
- if (cp->unack) {
- cp->flushed = 1;
- cp->vs = (cp->vs - cp->unack) & 7;
- for (qp = cp->rxasm; qp; qp = qp->anext ) {
- cp->sndtime[cp->vs] = 0;
- dup_p(&bp1, qp, 0, MAXINT16);
- send_packet(cp, I, CMD, bp1);
- }
- } else {
- try_send(cp,0,cp->mode);
- if ( cp->unack ) /* set 'flushed' state only if I-frame(s) were */
- cp->flushed = 1; /* generated by calling try_send() */
- }
-
- for (axp = Ax25_cb; axp != NULLAX25; axp = axp->next) {
- if (cp->iface == axp->iface) {
- if ( (axp != cp) && (!axp->flushed) ) {
- if (axp->unack) {
- axp->flushed = 1;
- axp->vs = (axp->vs - axp->unack) & 7;
- for (qp = axp->rxasm; qp; qp = qp->anext ) {
- axp->sndtime[axp->vs] = 0;
- dup_p(&bp1, qp, 0, MAXINT16);
- send_packet(axp, I, CMD, bp1);
- }
- }
- else {
- try_send(axp,0,cp->mode);
- if ( axp->unack )
- axp->flushed = 1; /* see above, same procedure */
- }
- }
- if (axp->state == CONNECTING) {
- axp->retries++;
- if (axp->retries > axp->iface->flags->retries) {
- axp->reason = LB_TIMEOUT;
- setaxstate(axp, DISCONNECTED);
- #ifdef NETROM
- nr_derate(axp);
- #endif
- } else {
- send_packet(axp,SABM,POLL,NULLBUF);
- }
- }
- }
- }
- }
-
-
- /*
- * setcall - convert callsign plus substation ID of the form
- * "KA9Q-0" to AX.25 (shifted) address format
- * Address extension bit is left clear
- * Return -1 on error, 0 if OK
- */
- int
- setcall(char *out,char *call)
- {
- int csize, i;
- unsigned ssid;
- char c, *dp;
-
- if(out == NULLCHAR || call == NULLCHAR || *call == '\0')
- return -1;
-
- /* Find dash, if any, separating callsign from ssid
- * Then compute length of callsign field and make sure
- * it isn't excessive
- */
- if((dp = strchr(call,'-')) == NULLCHAR)
- csize = strlen(call);
- else
- csize = (int)(dp - call);
-
- if(csize > ALEN)
- return -1;
-
- /* Now find and convert ssid, if any */
- if(dp != NULLCHAR) {
- dp++; /* skip dash */
- ssid = atoi(dp);
- if(ssid > 15)
- return -1;
- }
- else
- ssid = 0;
-
- /* Copy upper-case callsign, left shifted one bit */
- for(i = 0; i < csize; i++) {
- c = *call++;
- if(islower(c))
- c = toupper(c);
- *out++ = c << 1;
- }
-
- /* Pad with shifted spaces if necessary */
- for(; i < ALEN; i++)
- *out++ = ' ' << 1;
-
- /* Insert substation ID field and set reserved bits */
- *out = 0x60 | (ssid << 1);
- *out |= E;
- return 0;
- }
-
- int
- addreq(char *a,char *b)
- {
- if (*a++ != *b++) return 0;
- if (*a++ != *b++) return 0;
- if (*a++ != *b++) return 0;
- if (*a++ != *b++) return 0;
- if (*a++ != *b++) return 0;
- if (*a++ != *b++) return 0;
- return (*a & SSID) == (*b & SSID);
- }
-
- void
- addrcp(char *to,char *from)
- {
- *to++ = *from++;
- *to++ = *from++;
- *to++ = *from++;
- *to++ = *from++;
- *to++ = *from++;
- *to++ = *from++;
- *to = (*from & SSID) | 0x60;
- }
-
- /* Convert encoded AX.25 address to printable string */
- char *
- pax25(char *e,char *addr) {
- int i;
- char c, *cp = e;
-
- for(i=ALEN;i != 0;i--){
- c = (*addr++ >> 1) & 0x7f;
- if(c != ' ')
- *cp++ = c;
- }
- if ((*addr & SSID) != 0)
- sprintf(cp,"-%d",(*addr >> 1) & 0xf); /* ssid */
- else
- *cp = '\0';
- return e;
- }
-
- static int near
- put_reseq(struct ax25_cb *cp,struct mbuf *bp,int ns) {
- char *p;
- int cnt, sum;
- struct axreseq *rp;
- struct mbuf *tp;
-
- if (next_seq(ns) == cp->vr) return 0;
-
- rp = &cp->reseq[ns];
- if (rp->bp) return 0;
- for (sum = 0, tp = bp; tp; tp = tp->next) {
- cnt = tp->cnt;
- p = tp->data;
- while (cnt--)
- sum += uchar(*p++);
- }
- if (ns != cp->vr && sum == rp->sum) return 0;
- rp->bp = bp;
- rp->sum = sum;
- return 1;
- }
-
- void
- build_path(struct ax25_cb *cp,struct iface * ifp,
- char *newpath,int reverse,int newsrt) {
-
- char buf[10*AXALEN];
- int len, ndigi;
- char *ap, *tp, *myaddr = 0;
- struct axroute_tab *rp = 0;
-
- /*** find address length and copy address into control block ***/
-
- for (ap = newpath; !(ap[ALEN] & E); ap += AXALEN) ;
- cp->pathlen = (int)(ap - newpath + AXALEN);
-
- if (reverse) {
- addrcp(cp->path, newpath + AXALEN);
- addrcp(cp->path + AXALEN, newpath);
- for (tp = cp->path + 2 * AXALEN;
- tp < cp->path + cp->pathlen;
- tp += AXALEN, ap -= AXALEN)
- addrcp(tp, ap);
- } else {
- memcpy(cp->path, newpath, cp->pathlen);
- }
- /*** store iface pointer into control block ***/
- cp->iface = ifp;
-
- /*** save address for autorouting ***/
- if(reverse && ifp) axroute_add(cp,0);
-
- /*** find my digipeater address (use the last one) ***/
- for (ap = cp->path + 2 * AXALEN; ap < cp->path + cp->pathlen; ap += AXALEN) {
- if(!ifp) {
- for (ifp = Ifaces; ifp; ifp = ifp->next)
- if (ifp->output == ax_output && addreq(ifp->hwaddr,ap))
- break;
- }
- if (addreq(ap,ifp->hwaddr)) myaddr = ap;
- }
-
- if(!reverse) {
- /*** autorouting, remove all digipeaters before me ***/
- if (myaddr && myaddr > cp->path + 2 * AXALEN) {
- len = (int)((cp->path + cp->pathlen) - myaddr);
- memcpy(buf, myaddr, len);
- myaddr = cp->path + 2 * AXALEN;
- memcpy(myaddr, buf, len);
- cp->pathlen = 2 * AXALEN + len;
- }
- /*** add necessary digipeaters and find interface ***/
- ap = myaddr ? myaddr + AXALEN : cp->path + 2 * AXALEN;
- rp = axroute_tabptr(axptr((ap >= cp->path + cp->pathlen) ? cp->path : ap), 0);
- for (; rp; rp = rp->digi) {
- if (rp->digi && cp->pathlen < sizeof(cp->path)) {
- len = (int)((cp->path + cp->pathlen) - ap);
- if (len)
- memcpy(buf, ap, len);
- addrcp(ap, (char *) &rp->digi->call);
- if (len)
- memcpy(ap + AXALEN, buf, len);
- cp->pathlen += AXALEN;
- }
- cp->iface = rp->ifp;
- }
-
- if(!cp->iface)
- cp->iface = axroute_default_ifp;
-
- /*** replace my address with hwaddr of interface ***/
- if(myaddr != 0) {
- addrcp(cp->pathlen == 2 * AXALEN ? cp->path + AXALEN : cp->path + 2 * AXALEN,
- cp->iface ? cp->iface->hwaddr : Mycall);
- }
- }
-
- /*** clear all address bits ***/
-
- for (ap = cp->path; ap < cp->path + cp->pathlen; ap += AXALEN)
- ap[ALEN] = (ap[ALEN] & SSID) | 0x60;
-
- /*** set REPEATED bits for all digipeaters before and including me ***/
-
- if (myaddr)
- for (ap = cp->path + 2 * AXALEN; ap <= myaddr; ap += AXALEN)
- ap[ALEN] |= REPEATED;
-
- /*** mark end of address field ***/
- cp->path[cp->pathlen-1] |= E;
-
- if(!newsrt) return;
-
- init_timer(cp);
-
- /*** estimate round trip time ***/
- if (myaddr)
- ndigi = (int)((cp->path + cp->pathlen - myaddr) / AXALEN) + 1;
- else
- ndigi = cp->pathlen / AXALEN;
-
- cp->srt = (500 * cp->iface->flags->t1init * ndigi);
- cp->mdev = 0;
-
- reset_t1(cp);
- }
-
- int
- is_bud(char *icall,int store) {
- #define BTABLESIZE 23
-
- char bcall[AXALEN];
- struct btable_t { struct btable_t *next;
- char call[AXALEN];
- };
- static struct btable_t *btable[BTABLESIZE], *p, **tp;
-
- memcpy(bcall,icall,AXALEN);
- bcall[ALEN] = '0' << 1;
-
- tp = btable + hash_function(bcall,BTABLESIZE);
-
- for (p = *tp; p && !addreq(p->call, bcall); p = p->next) ;
-
- if (!p && store) {
- p = mxallocw(sizeof(*p));
- addrcp(p->call,bcall);
- p->next = *tp;
- *tp = p;
- }
- return (int) (p != 0);
- }
-
- static int near
- is_flexnet(char *call,int store) {
- #define FTABLESIZE 23
-
- struct ftable_t { struct ftable_t *next;
- char call[AXALEN];
- };
- static struct ftable_t *ftable[FTABLESIZE], *p, **tp;
-
- tp = ftable + hash_function(call,FTABLESIZE);
-
- for (p = *tp; p && !addreq(p->call, call); p = p->next) ;
-
- if (!p && store) {
- p = mxallocw(sizeof(*p));
- addrcp(p->call, call);
- p->next = *tp;
- *tp = p;
- }
- return (int) (p != 0);
- }
-
- static int near
- axproto_recv(struct iface *ifp,struct mbuf *bp,char repeated) {
- int cmdrsp, control, for_me, nr, ns, type, processed, seg, pid, ipcam;
- int dama_flag = DAMA - (bp->data[AXALEN+ALEN] & DAMA);
- struct ax25_cb *cp, *cpp;
- char *cntrlptr, temp[AXALEN], newcon;
-
- for(cntrlptr = bp->data + AXALEN;!(cntrlptr[ALEN] & E);cntrlptr += AXALEN) ;
-
- cntrlptr += AXALEN;
- control = uchar(*cntrlptr);
-
- if (control & 1) {
- if (control & 2)
- type = control & ~PF;
- else
- type = control & 0xf;
- } else
- type = I;
-
- for_me = addreq(bp->data,ifp->hwaddr);
- if((cp = find_ax25(bp->data + AXALEN,bp->data)) != NULLAX25 && !for_me) {
- for_me = 2;
- if(type == SABM && repeated) {
- free_p(bp);
- return;
- }
- }
- if (!for_me && (type == UI || addreq(bp->data, bp->data + AXALEN)
- || is_flexnet(bp->data, 0) || is_flexnet(bp->data + AXALEN, 0))) {
- axroute(NULLAX25, bp);
- return;
- }
- if((pid = uchar(cntrlptr[1])) == PID_FLEXNET)
- is_flexnet(bp->data + AXALEN, 1); /* */
-
- if ((bp->data[ALEN] & C) == (bp->data[ALEN + AXALEN] & C))
- cmdrsp = VERS1;
- else
- cmdrsp = ((bp->data[ALEN] & C) ? DST_C : SRC_C) | (control & PF);
-
- if(cp) {
- if (for_me == 1 || (for_me == 2 && cp->peer != NULLAX25)) {
- build_path(cp,ifp,bp->data,1,0);
- } else {
- addrcp(temp,bp->data); /* if the frame is not directly for */
- addrcp(bp->data,ifp->hwaddr); /* us, but for a user of our gateway */
- build_path(cp,ifp,bp->data,1,0); /* we MUST change the address field to */
- addrcp(cp->path + AXALEN,temp); /* make axrouting work! */
- if(cp->pathlen == 2 * AXALEN) /* DB3FL.910110 */
- cp->path[AXALEN + ALEN] |= E; /* set address field end bit */
- }
- cpp = cp->peer;
- newcon = 0;
- } else {
- cp = cr_ax25(bp->data + AXALEN,bp->data,ifp);
- build_path(cp, ifp, bp->data, 1, 1);
- newcon = 1;
-
- if (!for_me) {
- cp->peer = cpp = cr_ax25(bp->data,bp->data + AXALEN,NULLIF);
- cpp->peer = cp;
- build_path(cpp, NULLIF, bp->data, 0, 1);
- } else
- cpp = NULLAX25;
- }
- if (type == SABM) {
- int i;
- build_path(cp, ifp, bp->data, 1, 0);
- if (cp->unack)
- start_timer(&cp->t1);
- else
- stop_timer(&cp->t1);
- stop_timer(&cp->t2);
- stop_timer(&cp->t4);
- cp->polling = 0;
- cp->rnrsent = 0;
- cp->rejsent = 0;
- cp->remotebusy = 0;
- cp->vr = 0;
- cp->vs = cp->unack;
- cp->retries = 0;
- cp->flushed = 0;
- for (i = 0; i < 8; i++)
- if (cp->reseq[i].bp) {
- free_q(&cp->reseq[i].bp);
- cp->reseq[i].bp = NULLBUF;
- }
- if (dama_flag) {
- cp->dama = 1;
- if (newcon)
- dama_on(cp->iface);
- } else
- cp->dama = 0;
- }
-
- ipcam = 0;
- if (type == I) {
- /* IPCAM-feature - DB3FL.910104 */
- if((for_me == 1 || (for_me == 2 && cp->peer == NULLAX25))
- && pid == PID_NO_L3
- && uchar(cntrlptr[2]) == 0x45
- && uchar(cntrlptr[3]) == 0x00
- && uchar(cntrlptr[4]) < 0x02) {
- cntrlptr[1] = PID_IP;
- pid = PID_IP;
- ipcam = 1;
- }
- cp->mode = (pid == PID_NO_L3) ? STREAM : DGRAM;
- if(cpp)
- cpp->mode = cp->mode;
-
- if(pid == PID_IP) {
- struct arp_tab *arp;
-
- if ((arp = arp_add( /* src_ipaddr */
- get32(&cntrlptr[14]),ARP_AX25,cp->path,0,1+ipcam)) != NULLARP) {
- stop_timer(&arp->timer);
- set_timer(&arp->timer,0L);
- }
- }
- start_timer(&cp->t3);
- start_timer(&cp->t6);
- }
-
- /* every poll from master retriggers T6 timeout */
- if (cp->dama)
- start_timer(&cp->t6);
-
- if ((for_me == 0) && (cp->iface->flags->dama_slave))
- cp->iface->flags->dama_busy = 1;
-
- switch (cp->state) {
- case DISCONNECTED:
- if (for_me == 1 || (for_me == 2 && cp->peer == NULLAX25)) {
- if (type == SABM && cmdrsp != VERS1 && cp->r_upcall) {
- if (cp->dama)
- cp->iface->flags->dama_busy = 0;
- send_packet(cp, UA, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- if (cp->dama)
- cp->iface->flags->dama_busy = 1;
- setaxstate(cp, CONNECTED);
- start_timer(&cp->t3);
- start_timer(&cp->t6);
- } else {
- if (cmdrsp != RESP && cmdrsp != FINAL) {
- if (cp->dama)
- cp->iface->flags->dama_busy = 0;
- send_packet(cp, DM, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- if (cp->dama)
- cp->iface->flags->dama_busy = 1;
- }
- del_ax25(cp);
- }
- } else {
- if (type == SABM && cmdrsp != VERS1 && cpp->state == DISCONNECTED) {
- setaxstate(cpp, CONNECTING);
- } else if (type == SABM && cmdrsp != VERS1 && cpp->state == CONNECTING) {
- build_path(cpp, NULLIF, bp->data, 0, 1);
- send_packet(cpp, SABM, POLL, NULLBUF);
- } else {
- if (cmdrsp != RESP && cmdrsp != FINAL)
- send_packet(cp, DM, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- if (cpp->state == DISCONNECTED) {
- del_ax25(cpp);
- del_ax25(cp);
- }
- }
- }
- break;
-
- case CONNECTING:
- switch (type) {
- case I:
- case RR:
- case RNR:
- case REJ:
- break;
- case SABM:
- if (cmdrsp != VERS1) {
- if (cp->dama)
- cp->iface->flags->dama_busy = 0;
- send_packet(cp, UA, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- if (cp->dama)
- cp->iface->flags->dama_busy = 1;
- setaxstate(cp, CONNECTED);
- }
- break;
- case UA:
- if (cmdrsp != VERS1) {
- start_timer(&cp->t3);
- start_timer(&cp->t6);
- if (dama_flag) {
- cp->dama = 1;
- dama_on(cp->iface);
- } else {
- cp->dama = 0;
- }
- setaxstate(cp, CONNECTED);
- } else {
- if (cpp && cpp->state == DISCONNECTED)
- send_packet(cpp, DM, FINAL, NULLBUF);
- cp->reason = LB_DM;
- setaxstate(cp, DISCONNECTING);
- }
- break;
- case DISC:
- send_packet(cp, DM, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- case DM:
- case FRMR:
- if (cpp && cpp->state == DISCONNECTED)
- send_packet(cpp, DM, FINAL, NULLBUF);
- cp->reason = LB_DM;
- setaxstate(cp, DISCONNECTED);
- #ifdef NETROM
- nr_derate(cp); /* TEST */
- #endif
- break;
- }
- break;
-
- case CONNECTED:
- switch (type) {
- case I:
- case RR:
- case RNR:
- case REJ:
- stop_timer(&cp->t1);
- nr = control >> 5;
- if (((cp->vs - nr) & 7) < cp->unack) {
- if (!cp->polling) {
- cp->retries = 0;
- cp->flushed = 0;
- if (cp->sndtime[(nr-1)&7]) {
- int32 rtt = msclock() - cp->sndtime[(nr-1)&7];
- int32 abserr = rtt > cp->srt ? rtt - cp->srt : cp->srt - rtt;
- cp->srt = ((AGAIN-1) * cp->srt + rtt + (AGAIN/2)) / AGAIN;
- cp->mdev = ((DGAIN-1) * cp->mdev + abserr + (DGAIN/2)) >> 3;
- reset_t1(cp);
- }
- if (cp->cwind < cp->iface->flags->maxframe) {
- cp->mdev += (cp->srt / cp->cwind) >> 3;
- cp->cwind++;
- }
- }
- while (((cp->vs - nr) & 7) < cp->unack) {
- cp->rxasm = free_p(cp->rxasm);
- cp->unack--;
- }
- if (cpp && cpp->rnrsent && !busy(cpp))
- send_ack(cpp, RESP);
- }
- if (type == I) {
- ns = (control >> 1) & 7;
- pullup(&bp, NULLCHAR, cntrlptr - bp->data + 1 + (cp->mode == STREAM));
- if (!bp)
- bp = ambufw(0);
- if (put_reseq(cp, bp, ns))
- while ((bp = cp->reseq[cp->vr].bp) != NULLBUF) {
- cp->reseq[cp->vr].bp = NULLBUF;
- cp->vr = next_seq(cp->vr);
- cp->rejsent = 0;
- processed = 0;
- if(for_me == 1 && uchar(cntrlptr[1]) != PID_NO_L3) {
- processed = 1;
- pid = PULLCHAR(&bp);
- if(cp->segremain != 0) {
- /* Reassembly in progress; continue */
- seg = PULLCHAR(&bp);
- if(pid == PID_SEGMENT && (seg & SEG_REM) == cp->segremain - 1) {
- /* Correct, in-order segment */
- append(&cp->segasm,bp);
- if((cp->segremain = (seg & SEG_REM)) == 0) {
- /* Done; kick it upstairs */
- bp = cp->segasm;
- cp->segasm = NULLBUF;
- cp->segremain = 0;
- pid = PULLCHAR(&bp);
- switch(pid) {
- case PID_IP:
- ip_route(ifp,ifp,bp,0);
- break;
- #ifdef AX25
- case PID_ARP:
- arp_input(ifp,bp);
- break;
- #endif
- #ifdef NETROM
- case PID_NETROM:
- nr_route(bp,cp);
- break;
- #endif
- }
- }
- } else {
- /* Error! */
- free_q(&cp->segasm);
- cp->segasm = NULLBUF;
- cp->segremain = 0;
- free_p(bp);
- }
- } else {
- /* No reassembly in progress */
- if(pid == PID_SEGMENT) {
- /* Start reassembly */
- seg = PULLCHAR(&bp);
- if(!(seg & SEG_FIRST)) {
- free_p(bp); /* not first seg - error! */
- } else {
- /* Put first segment on list */
- cp->segremain = seg & SEG_REM;
- cp->segasm = bp;
- }
- } else {
- /* Normal frame; send upstairs */
- switch(pid) {
- case PID_IP:
- ip_route(ifp,ifp,bp,0);
- break;
- #ifdef AX25
- case PID_ARP:
- arp_input(ifp,bp);
- break;
- #endif
- #ifdef NETROM
- case PID_NETROM:
- nr_route(bp,cp);
- break;
- #endif
- }
- }
- }
- }
- if(!processed) {
- if (for_me && cpp == NULLAX25) {
- cp->rcvcnt += len_p(bp);
- if(cp->user == 0 || Axi_sock == -1) { /* */
- free_p(bp); /* */
- } else { /* */
- if (cp->mode == STREAM)
- append(&cp->rxq, bp);
- else
- enqueue(&cp->rxq, bp);
- } /* */
- } else {
- send_ax25(cpp, bp, cp->mode);
- }
- }
- }
- if (cmdrsp == POLL) {
- if (cp->dama)
- dama_flush(cp);
- send_ack(cp, FINAL);
- cp->iface->flags->dama_busy = 1;
- } else {
- if(!cp->iface->flags->t2init)
- send_ack(cp, RESP);
- else {
- set_timer(&cp->t2,cp->iface->flags->t2init * 1000L);
- start_timer(&cp->t2);
- }
- }
- if (cp->r_upcall && cp->rcvcnt)
- (*cp->r_upcall)(cp, cp->rcvcnt);
- } else {
- if (cmdrsp == POLL) {
- if (cp->dama)
- dama_flush(cp);
- send_ack(cp, FINAL);
- cp->iface->flags->dama_busy = 1;
- }
- if (cp->polling && cmdrsp == FINAL)
- cp->retries = cp->polling = cp->flushed = 0;
- if (type == RNR) {
- if (!cp->remotebusy)
- cp->remotebusy = currtime;
- set_timer(&cp->t4,cp->iface->flags->t4init * 1000L);
- start_timer(&cp->t4);
- cp->cwind = 1;
- } else {
- cp->remotebusy = 0;
- stop_timer(&cp->t4);
- if (cp->unack && type == REJ) {
- int old_vs;
- struct mbuf *bp1;
- old_vs = cp->vs;
- cp->vs = (cp->vs - cp->unack) & 7;
- cp->sndtime[cp->vs] = 0;
- dup_p(&bp1, cp->rxasm, 0, MAXINT16);
- send_packet(cp, I, CMD, bp1);
- cp->vs = old_vs;
- cp->cwind = 1;
- } else if (cp->unack && cmdrsp == FINAL) {
- struct mbuf *bp1, *qp;
- cp->vs = (cp->vs - cp->unack) & 7;
- for (qp = cp->rxasm; qp; qp = qp->anext) {
- cp->sndtime[cp->vs] = 0;
- dup_p(&bp1, qp, 0, MAXINT16);
- send_packet(cp, I, CMD, bp1);
- }
- }
- }
- }
- try_send(cp, 1, cp->mode);
- if (cp->polling || cp->unack && !cp->remotebusy && !cp->dama)
- start_timer(&cp->t1);
- if (cp->closed && !cp->txq && !cp->unack
- || cp->remotebusy && cp->remotebusy + 900l < currtime)
- setaxstate(cp, DISCONNECTING);
- break;
- case SABM:
- if (cp->dama)
- cp->iface->flags->dama_busy = 0;
- send_packet(cp, UA, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- try_send(cp, 1, cp->mode);
- if (cp->dama)
- cp->iface->flags->dama_busy = 1;
- break;
- case DISC:
- if (cp->dama)
- cp->iface->flags->dama_busy = 0;
- send_packet(cp, DM, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- /* send_packet(cp, UA, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF); */
- if (cp->dama)
- cp->iface->flags->dama_busy = 1;
- case DM:
- if (cp->dama && (--ifp->flags->dama_slave) == 0)
- dama_off(ifp);
- setaxstate(cp, DISCONNECTED);
- break;
- case UA:
- cp->remotebusy = 0;
- stop_timer(&cp->t4);
- if (cp->unack)
- start_timer(&cp->t1);
- try_send(cp, 1, cp->mode);
- break;
- case FRMR:
- setaxstate(cp, DISCONNECTING);
- break;
- }
- break;
-
- case DISCONNECTING:
- switch (type) {
- case I:
- case RR:
- case RNR:
- case REJ:
- case SABM:
- if (cp->dama) {
- cp->iface->flags->dama_busy = 0;
- send_packet(cp, DISC, POLL, NULLBUF);
- cp->iface->flags->dama_busy = 1;
- }
- else {
- if (cmdrsp != RESP && cmdrsp != FINAL)
- send_packet(cp, DM, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- }
- break;
- case DISC:
- if (cp->dama)
- cp->iface->flags->dama_busy = 0;
- send_packet(cp, DM, (cmdrsp == POLL) ? FINAL : RESP, NULLBUF);
- if (cp->dama)
- cp->iface->flags->dama_busy = 1;
- case DM:
- case UA:
- case FRMR:
- if (cp->dama && (--ifp->flags->dama_slave) == 0)
- dama_off(ifp);
- setaxstate(cp, DISCONNECTED);
- break;
- }
- break;
- }
- free_p(bp);
- return;
- }
-
- /* set tnc to full duplex if it's our first connection in mode DAMA */
- static void near dama_on(struct iface *ifp) {
- char *argv[] = {"5","1"};
-
- ifp->flags->dama_busy = 1;
- if (ifp->flags->dama_slave++ || ifp->ioctl == NULLFP)
- return;
- (*ifp->ioctl)(ifp,2,argv);
- }
-
- /* set normal tnc parameter (csma) */
- static void near dama_off(struct iface *ifp) {
- char *argv[] = {"5","0"};
-
- ifp->flags->dama_busy = 0;
- ifp->flags->dama_slave = 0;
- if (ifp->ioctl != NULLFP)
- (*ifp->ioctl)(ifp,2,argv);
- }
-
- #ifdef AXIP
- static int
- axip_stop(iface)
- struct iface *iface;
- {
- axipaddr[iface->dev] = 0;
- return 0;
- }
-
- /* attach a fake AX.25 interface for AX.25 on top of IP */
- /* argv[0] == "axip"
- * argv[1] == name of new interface
- * argv[2] == MTU
- * argv[3] == hostname of remote end of wormhole
- * argv[4] == optional callsign is not necessary when using WNOS
- */
- int
- axip_attach(int argc,char *argv[],void *p) {
- int i;
- struct iface *ifp;
-
- if(if_lookup(argv[1]) != NULLIF) {
- tprintf(Ifexist,argv[1]);
- return -1;
- }
- for(i = 0; i < NAX25; ++i)
- if(axipaddr[i] == 0)
- break;
- if(i == NAX25) {
- tprintf("Max %d AXIP ifaces\n",NAX25);
- return -1;
- }
- if((axipaddr[i] = resolve(argv[3])) == 0) {
- tprintf(Badhost,argv[3]);
- return -1;
- }
- ifp = (struct iface *)mxallocw(sizeof(struct iface));
- ifp->dev = i;
- ifp->addr = Ip_addr;
- ifp->name = strxdup(argv[1]);
- ifp->mtu = atoi(argv[2]);
- setencap(ifp,"AX25");
- ifp->hwaddr = strxdup(Mycall);
- ifp->raw = axip_raw;
- ifp->stop = axip_stop;
- init_maxheard(ifp);
- init_flags(ifp);
- ifp->niface = Niface++;
- ifp->next = Ifaces;
- Ifaces = ifp;
- return 0;
- }
- #endif /* AXIP */
-